package com.sr.maven.util;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

/**
 * 功能1：从数据源获取数据库链接
 * 功能2：将数据源获取到数据库连接绑定到本地线程 ThreadLocal
 * 功能3：释放线程时和本地超线程解除绑定
 */
public class JDBCUtils {

    //数据源成员变量，设置为静态资源，保证大对象的单例性，同时保证静态方法中可以访问
    private static DataSource dataSource;

    //由于ThreadLocal对象需要作为绑定数据时K-v对中的key，所以需要保证唯一性
    //加static声明为静态资源可保证唯一性
    private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();

    //在静态代码块中初始化数据源
    static {

        try {
            //从jdbc.properties中读取链接数据库的信息
            //为了保证程序代码的可移植性，需要基于一个确定的基准来读取这个文件
            //确定的基准，类路径的根目录，resource目录下的内容经过构建后打包操作会确定放在 WEB-INF/classes目录下。
            //WEB-INF/classes 目录存放编译好的*.class字节码文件，所以这个目录我们就称之为类路径
            //类路径无论是在本地运行还是在服务器端运行都是一个确定的路径
            //具体操作代码
            //1.获取当前类的类加载器
            ClassLoader classLoader = JDBCUtils.class.getClassLoader();
            //2.通过类加载器对象从类路径根目录下读取文件
            InputStream stream = classLoader.getResourceAsStream("jdbc.properties");
            //3.使用Properties类封装属性文件中的数据
            Properties properties = new Properties();
            properties.load(stream);
            //4.根据Properties对象（已经封装了数据库连接信息）来创建数据源对象
            dataSource = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
            //为了避免在真正抛出异常后，catch块捕捉获取到异常掩盖问题
            //这里将所捕获的异常封装为运行时异常继续抛出去
            throw new RuntimeException(e);
        }
    }

    public static Connection getConnection() {
        Connection connection;
        try {
            //1.尝试从当前线程检查是否已存在绑定的Connection对象
             connection = threadLocal.get();
            //2.检查Connection对象是否为null
            if (connection == null) {
                connection = dataSource.getConnection();

                //绑定到当前线程
                threadLocal.set(connection);
            }
        }catch (SQLException e){
            e.printStackTrace();
            throw  new RuntimeException(e);
        }
        return connection;
    }


    public static void  releaseConnection(Connection connection){

        if(connection!=null){
            try {
                connection.close();
                threadLocal.remove();
            } catch (SQLException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }
    }
}
